package com.xinchao.filter;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.xinchao.config.CustomProperties;
import com.xinchao.core.constant.ClientConstant;
import com.xinchao.core.constant.RequestConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录过滤器
 *
 * @author dxy
 * @date 2018/7/5 12:39
 */
public class LoginFilter implements Filter {

	public static Logger logger = LoggerFactory.getLogger(LoginFilter.class);

	private static final String LOGIN = "/web/login";

	private static final String DOLOGIN = "/web/doLogin";

	private static final String LOGOUT = "/web/logout";

	@Autowired
	private CustomProperties customProperties;


	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		ServletContext servletContext = filterConfig.getServletContext();
		ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
		customProperties = (CustomProperties) ctx.getBean("customProperties");
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;

		//上下文路径
		String contextPath = httpRequest.getContextPath();
		String requestURI = httpRequest.getRequestURI();
		//放行静态资源
		if (isPassStaticSouorce(requestURI)) {
			chain.doFilter(httpRequest, httpResponse);
			return;
		}
		//goLogin、login,直接放行
		if (isPassUrl(requestURI, contextPath)) {
			chain.doFilter(httpRequest, httpResponse);
			return;
		}
		// TODO 无法穷举URI,故无法获取更多的监控信息，spring-boot-admin监控请求,直接放行
		if ( isMonitorUrl(requestURI, contextPath) ) {
			chain.doFilter(httpRequest, httpResponse);
			return;
		}
		//验证用户是否登录
		Object user = httpRequest.getSession().getAttribute(RequestConstant.SESSION_KEY_USER);
		if (user == null) {
		    //未登录或超时，判断是否ajax请求
            if (isAjax(httpRequest)) {
                writeNeedLoginResultForAjax(httpResponse);
            } else {
                httpResponse.sendRedirect(contextPath + LOGIN);
            }
			return;
		} else {
			chain.doFilter(httpRequest, httpResponse);
			return;
		}
	}

	@Override
	public void destroy() {

	}

	private boolean isMonitorUrl(String requestURI,String contextPath){
		if (requestURI.startsWith(contextPath + "/health")
				|| requestURI.startsWith(contextPath + "/status")
				|| requestURI.startsWith(contextPath + "/actuator")
				|| requestURI.startsWith(contextPath + "/info")
				|| requestURI.startsWith(contextPath + "/env")
				|| requestURI.startsWith(contextPath + "/metrics")
				|| requestURI.startsWith(contextPath + "/httptrace")
				|| requestURI.startsWith(contextPath + "/auditevents")
				|| requestURI.startsWith(contextPath + "/threaddump")
				|| requestURI.startsWith(contextPath + "/heapdump")
				|| requestURI.startsWith(contextPath + "/jolokia")
				|| requestURI.startsWith(contextPath + "/beans")
				|| requestURI.startsWith(contextPath + "/conditions")
				|| requestURI.startsWith(contextPath + "/configprops")
				|| requestURI.startsWith(contextPath + "/scheduledtasks")
				|| requestURI.startsWith(contextPath + "/mappings")
				|| requestURI.startsWith(contextPath + "/loggers")) {
			return true;
		}
		return false;
	}

    /**
     * 判断是否是ajax请求
     *
     * @param request
     * @return
     */
    private static boolean isAjax(HttpServletRequest request) {
        boolean isAjax = false;
        if (request.getHeader("x-requested-with") != null && "XMLHttpRequest".equals(request.getHeader("x-requested-with"))) {
            isAjax = true;
        }
        return isAjax;
    }

	/**
	 * 未登录时对ajax请求的处理
	 *
	 * @param response
	 */
	private void writeNeedLoginResultForAjax(HttpServletResponse response) {
		try {
			Map<String, Object> map = new HashMap<>(3);
			ObjectMapper json = new ObjectMapper();
			map.put("code", ClientConstant.CODE_NOT_LOGIN);
			map.put("msg", ClientConstant.MSG_NOT_LOGIN);
			map.put("loginUrl", customProperties.getLoginUrl());
			response.setContentType("text/javascript;charset=utf-8");
			response.getWriter().write(json.writeValueAsString(map));
			response.sendError(ClientConstant.CODE_NOT_LOGIN, "访问被限制，请先登录");
		} catch (IOException e) {
			logger.error("LoginFilter writeNeedLoginResultForAjax 拦截到ajax未登录时处理出现异常：" + e.getMessage());
		}
	}


    /**
     * 是否直接通过的路径
     *
     * @param requestURI  请求
     * @param contextPath 上下文路径
     * @return
     */
    private boolean isPassUrl(String requestURI, String contextPath) {
        if (requestURI.equals(contextPath + LOGIN)
                || requestURI.equals(contextPath + DOLOGIN)
                || requestURI.equals(contextPath + LOGOUT)) {
            return true;
        }
        return false;
    }

    /**
     * 是否直接通过的资源
     *
     * @param requestURI  请求
     * @return
     */
    private boolean isPassStaticSouorce(String requestURI) {
        if (requestURI.endsWith(".js")
                || requestURI.endsWith(".css")
                || requestURI.endsWith(".img")
                || requestURI.endsWith(".png")) {
            return true;
        }
        return false;
    }
}
